iT邦幫忙

2023 iThome 鐵人賽

DAY 30
0
Mobile Development

React Native CLI 開發心法系列 第 30

DAY 30 React Native 版本升級實戰 : 填坑之旅

  • 分享至 

  • xImage
  •  

React Natvie 版本升級一直是開發上很痛苦的一部分,常常一升級就會有 dependency 壞掉,修了東就壞了西的窘況,在這篇文章中,筆者會分享升級 React Natvie 版本需要注意的什麼?哪時候要升版?最後藉由升級實戰來分享該如何解決升版遇到的每個問題。

什麼時候該更新 React Native 版本了?

雖然以穩定上線的產品角度來說應該要秉持著能動就不升版的精神,但是理想的狀態還是會希望產品的版號還是依 react-native-releases 中所提及的Support level 為主,這邊指的是 React Native 開發團隊所支援的更新的版本,當你的專案版號已經是 Unsupported 的狀態,就要注意了,因為有些 dependency 也會隨著 React Native 版本升級漸漸不支援舊的版本,這時就該考慮是否將整個 React Native 專案升級了。

Version Type Support level
0.73.x Next version Future
0.72.x Latest stable Active
0.71.x Previous (-1) minor series Active
0.70.x Previous (-2) minor series End of Cycle
<=0.69.x Old minor series Unsupported
以上圖表取自 react-native-releases
不過就筆者經驗來說還是不建議升到 Latest stable 的 0.72 版本,因為有很多套件不一定可以立刻支援到 0.72 版本。

更新要注意什麼?

  • 了解更新內容:檢視從舊的版本到新的版本這中間的內容改了什麼。
  • 最小幅度的更新:盡量以最小的粒度做更新,一次更新只更新一個次版號,當更新遇到問題時較能把問題限縮在一個範圍內。
  • 充裕的時間:更新專案版本必須在充裕的時間,因為有太多不可預期的 bug 要解決,同時也要保留測試的時間。
  • 備份:要先有備份!有時候更新不一定成功,還可能越更越有問題,而這個問題不是你能解決的,有可能是需要等待 dependency 或 React Native 的維護人員修正的,有備份至少還有辦法回復到原來的狀態。

版本升級實戰 - 從 0.70.13 遷移到 0.71.13

以下筆者將實際更新 React Native 的過程與思路紀錄下來。

了解要更新的版本內容

首先,我們要先瞭解這次要更新的版號的內容是什麼?可以從 React Native 官方的 change log 或是 blog 中查找,或是在 DAY 4 接手 React Native CLI 專案應該知道的事 - React Native 版本 所整理的版本內容得知,以這次要更新的目標版本0.71 幾個重要的更新為例:

預設使用 TypeScript
新增 Flexbox gap 屬性

從上我們可以得知兩件事,那就是 React Native 本身開始支援 TypeScript,這代表可能在專案升級到 0.71 後程式碼會出現型別的錯誤,可能會花一些時間去排除型別錯誤的問題,Flexbox gap 的屬性可以改變過去排版上的不足,雖然升級的過程中不需要用到,但是在未來佈局時可以更方便的排版。

使用 React Native Upgrade Helper

React Native 有推出一個升級版本的工具 React Native Upgrade Helper,選定好專案的版本與目標的升級版本,下方就會顯示兩個版本差異的程式碼。
https://ithelp.ithome.com.tw/upload/images/20231006/20162496SNQwqdwpEb.png

更新所有 dependencies

https://ithelp.ithome.com.tw/upload/images/20231006/20162496bAJRcJIPXM.png
依照提供需要更新的 dependencies 跟相對應的版本開始一個一個手動升級,如果有些套件的版號已經比文件裡建議的版號高或相同就不用更新了:

yarn add  react-native@0.71.13
yarn add --dev eslint@8.19.0
yarn add --dev prettier@2.4.1
yarn add --dev  @react-native-community/eslint-config@3.2.0
yarn add --dev @tsconfig/react-native@2.0.2
yarn add --dev @types/react@18.0.24
yarn add --dev metro-react-native-babel-preset@0.73.10

最後,更新 iOS Pod

cd ios && pod install

更新與 Native code 無關的內容

根據這份文件,我們可以拆分為在 android/ 目錄底下的原生程式碼跟 ios/目錄底下的原生程式碼以及在這兩者之外的非原生程式碼,由於原生程式碼更新的部分是最麻煩而且有可能會噴一堆錯,所以先把非原生的程式碼根據文件提供的內容修改。

更新 iOS Native code

接著,我們開始依照文件內容修改 iOS 的部分,會先修改 iOS 的原因在於升級時 iOS 相對 Android 比較不會有太多令人驚喜的錯誤!
文件上的 RnDiffApp 要自己帶入你的專案名稱。
所以依照文件建議修改了

  • ios/Podfile
  • ios/RnDiffApp/AppDelegate
  • ios/RnDiffApp/AppDelegate.mm :這裡要注意 self.moduleName = @"RnDiffApp"; RnDiffApp 是要填入你應用程式的名稱
  • ios/RnDiffApp/Info.plist
  • ios/RnDiffApp.xcodeproj/project.pbxproj:這個檔案不用改,就是你 Xcode 介面設定檔
    改完後記得更新 iOS Pod
cd ios && pod install
yarn run iOS

看看你的 iOS APP 是否正確的安裝在模擬器上。

更新 Android Native code

Android 也是照著文件進行更新,但是建議使用 Android Studio 進行更新。
https://ithelp.ithome.com.tw/upload/images/20231006/20162496J4qsa28P0y.png
在更新完程式碼時,記得點一下右上方的藍色小象圖示,以同步更新專案的 Gradle 檔案。同時在更新的過程中遇到 App Id 的部分一樣要記得帶入自己專案的 App Id。

照著文件更新完成後

yarn run android

開始發生錯誤了~

填坑之旅

錯誤一

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

See https://docs.gradle.org/7.5/userguide/command_line_interface.html#sec:command_line_warnings
145 actionable tasks: 6 executed, 139 up-to-date
ERROR:/Users/ashely/App/android/app/build/ASSETS/createBundleDevelopmentDebugJsAndAssets/CodePushHash /Users/ashely/App/android/app/build/ASSETS/createBundleDevelopmentDebugJsAndAssets/CodePushHash: Resource and asset merger: Duplicate resources

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:mergeDevelopmentDebugAssets'.
> /Users/ashely/App/android/app/build/ASSETS/createBundleDevelopmentDebugJsAndAssets/CodePushHash	/Users/ashely/App/android/app/build/ASSETS/createBundleDevelopmentDebugJsAndAssets/CodePushHash: Error: Duplicate resources

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 9s

在這個錯誤訊息中可以找到一個關鍵字 CodePushHash: Error: Duplicate resources ,因此可以推斷說 react-native-code-push 可能有問題,果然在 react-native-code-push 的 issue 中找到也有人有一樣的問題: https://github.com/oblador/react-native-vector-icons/issues/1443

解決方式

將原來 react-native-code-push 的版本從 7.1.0 升級到 8.0.0 。

cd android && ./gradlew clean

同步 Gradle 檔案

yarn run android

又失敗了之錯誤二

warn Package react-native-vector-icons contains invalid configuration: "dependency.assets" is not allowed. Please verify it's properly linked using "react-native config" command and contact the package maintainers about this.

看起來是 react-native-vector-icons 的問題,一樣找 issue 果然也有人遇到:https://github.com/oblador/react-native-vector-icons/issues/1443

解決方式

將原來 react-native-vector-icons 的版本從 8.1.0 升級到 10.0.0 。

cd android && ./gradlew clean

同步 Gradle 檔案

yarn run android

然後又失敗了之錯誤三

* What went wrong:
Execution failed for task ':app:mergeDevelopmentDebugAssets'.
> [fonts/Fontisto.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Fontisto.ttf	[fonts/Fontisto.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Fontisto.ttf: Error: Duplicate resources
  [fonts/Octicons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Octicons.ttf	[fonts/Octicons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Octicons.ttf: Error: Duplicate resources
  [fonts/Feather.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Feather.ttf	[fonts/Feather.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Feather.ttf: Error: Duplicate resources
  [fonts/Entypo.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Entypo.ttf	[fonts/Entypo.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Entypo.ttf: Error: Duplicate resources
  [fonts/FontAwesome5_Brands.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf	[fonts/FontAwesome5_Brands.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/FontAwesome5_Brands.ttf: Error: Duplicate resources
  [fonts/MaterialCommunityIcons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf	[fonts/MaterialCommunityIcons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/MaterialCommunityIcons.ttf: Error: Duplicate resources
  [fonts/AntDesign.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/AntDesign.ttf	[fonts/AntDesign.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/AntDesign.ttf: Error: Duplicate resources
  [fonts/Foundation.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Foundation.ttf	[fonts/Foundation.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Foundation.ttf: Error: Duplicate resources
  [fonts/Ionicons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Ionicons.ttf	[fonts/Ionicons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Ionicons.ttf: Error: Duplicate resources
  [fonts/FontAwesome5_Solid.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf	[fonts/FontAwesome5_Solid.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/FontAwesome5_Solid.ttf: Error: Duplicate resources
  [fonts/FontAwesome5_Regular.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf	[fonts/FontAwesome5_Regular.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/FontAwesome5_Regular.ttf: Error: Duplicate resources
  [fonts/FontAwesome.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/FontAwesome.ttf	[fonts/FontAwesome.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/FontAwesome.ttf: Error: Duplicate resources
  [fonts/Zocial.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Zocial.ttf	[fonts/Zocial.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Zocial.ttf: Error: Duplicate resources
  [fonts/EvilIcons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/EvilIcons.ttf	[fonts/EvilIcons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/EvilIcons.ttf: Error: Duplicate resources
  [fonts/SimpleLineIcons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/SimpleLineIcons.ttf	[fonts/SimpleLineIcons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/SimpleLineIcons.ttf: Error: Duplicate resources
  [fonts/MaterialIcons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/MaterialIcons.ttf	[fonts/MaterialIcons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/MaterialIcons.ttf: Error: Duplicate resources

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 38s

透過錯誤訊息中的 ReactNativeVectorIcons 關鍵字得知又是 react-native-vector-icons 的問題!一樣在 issue 中搜尋發現:https://github.com/oblador/react-native-vector-icons/issues/1490#issuecomment-1457046459

解決方式

\android\app\src\main\assets\fonts\ 的字型整個刪掉。

cd android && ./gradlew clean

同步 Gradle 檔案

yarn run android

然後又又失敗了之錯誤四

/Users/ashely/App/android/app/src/debug/java/com/app/ReactNativeFlipper.java:32: error: duplicate class: com.app.ReactNativeFlipper
public class ReactNativeFlipper {
       ^
Note: /Users/ashely/App/android/app/src/main/java/com/app/MainApplication.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 error

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileDevelopmentDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 9s
error Failed to install the app.
info Run CLI with --verbose flag for more details.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

截取部分錯誤內容丟 google 得到了:https://github.com/facebook/react-native/issues/36362#issuecomment-1454845471

解決方式

\android\app\src\底下新增 release 資料夾並且把 new ReactNativeFlipper 檔案搬到這個路徑底下。

cd android && ./gradlew clean

同步 Gradle 檔案

yarn run android

終於 build 成功了

但是因為剛剛有升級了某些套件的版本,所以在 iOS 的部分也要記得更新 pod!

cd ios && pod install
yarn run iOS

沒問題的話就進入最後的測試了。

測試

  1. 測試 iOS 跟 Android 的 debug mode 應用程式是否正常。
  2. 測試是否能正常打包 iOS 跟 Android release mode 的應用程式,並且能順利安裝在實體裝置上。
  3. 在實體的手機測試既有的功能是否能正常運作。

結語

如果一切都順利的話,那就恭喜你搞定了一大堆的錯誤成功升級!也升級了你的 debug 能力!

有沒有可能升級失敗?
有!
而且機率很高!

之前筆者就有經驗升級到某個版本後,某個套件就壞了,查了一下該套件的 issue ,也有人在遇到同樣的問題,但就是遲遲等不到維護的人進行 hot fix 而這時也沒有能力去提出修正的 PR ,那就只好放棄這次的升級了。
曾經也遇到專案用的套件已經超過 3 年沒人維護了,在打包時錯誤訊息指出該套件的某個 API 已經棄用了,這時也只好硬著頭皮自己寫 patch 去修改,寫 patch 的方式已經在先前分享過了 Day 9 修改 npm 套件的好幫手  -  patch-package

總之,升級 React Native 版本有一定的風險,升級前最好還是一再評估!


上一篇
DAY 29 React Native 效能優化:提升效能實戰(三)& 效能優化總結
下一篇
DAY31 - 鐵人賽回顧與完賽感想
系列文
React Native CLI 開發心法31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言